from fastapi import APIRouter, Depends, HTTPException, File, UploadFile,Form
from fastapi.responses import  StreamingResponse
from sqlalchemy.orm import Session
from database import SessionLocal
from crud.material import create_material, get_material, get_all_materials, update_material, delete_material
from schemas.material import MaterialCreate, MaterialResponse, MaterialContent
from models.models import LearnUser
import os
from pathlib import Path
from utils.auth import get_current_user
from utils.log_manager import app_logger
from utils.utils import get_pdf_reader
from io import BytesIO
from PyPDF2 import PdfWriter
from urllib.parse import quote

router = APIRouter(prefix="/materials", tags=["Materials"])

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# 获取main.py所在的根目录路径
ROOT_DIR = Path(__file__).parent.parent
# 文件上传目录相对于根目录的路径
UPLOAD_DIR = ROOT_DIR / "static" 
# 确保上传目录存在
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)

@router.post("/", response_model=MaterialResponse)
async def add_material(
    title: str = Form(...), 
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user: LearnUser = Depends(get_current_user)
):
    # 生成唯一的文件名（使用原始文件名）
    file_path = UPLOAD_DIR / "docs" /file.filename
    
    # 保存上传的文件
    try:
        contents = await file.read()
        with open(file_path, "wb") as f:
            f.write(contents)
    except Exception as e:
        app_logger.error(f"Failed to upload file: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Failed to upload file: {str(e)}")
    
    # 存储到数据库的路径应该是相对于static目录的路径
    relative_path = os.path.join("docs", file.filename)
    # 创建材料记录
    material_data = MaterialCreate(
        user_id=current_user.id,
        title=title,
        file_path=relative_path,
    )
    response = create_material(db, material_data)
    return MaterialResponse(
        id=response.id,
        title=response.title,
        created_at=response.created_at
    )
@router.get("/{material_id}/info")
def get_material_info(material_id: int, db: Session = Depends(get_db), current_user: LearnUser = Depends(get_current_user)):
    material = get_material(db, material_id, current_user.id)
    if not material:
        raise HTTPException(status_code=404, detail="Material not found")
    
    file_path = UPLOAD_DIR / material.file_path
    pdf_path = Path(file_path)
    if not pdf_path.exists():
        return HTTPException(status_code=404, detail="Material not found")

    from PyPDF2 import PdfReader
    reader = PdfReader(pdf_path)
    total_pages = len(reader.pages)

    return {"total_pages": total_pages}


@router.get("/{material_id}/{block_index}")
def read_material_block(
    material_id: int, 
    block_index: int,
    db: Session = Depends(get_db),
    current_user: LearnUser = Depends(get_current_user)
):
    # 参数验证
    if block_index < 0:
        raise HTTPException(status_code=400, detail="块索引不能为负数")

    # 获取材料信息
    material = get_material(db, material_id, current_user.id)
    if not material:
        raise HTTPException(status_code=404, detail="材料不存在")
    
    # 验证文件路径
    file_path = UPLOAD_DIR / material.file_path
    if not file_path.exists():
        raise HTTPException(status_code=404, detail="PDF文件不存在")

    # 初始化PDF阅读器（带缓存）
    reader = get_pdf_reader(str(file_path))
    
    # 计算分页范围
    BLOCK_SIZE = 5
    total_pages = len(reader.pages)
    start_page = block_index * BLOCK_SIZE
    end_page = min(start_page + BLOCK_SIZE, total_pages)

    # 验证块索引有效性
    if start_page >= total_pages or block_index < 0:
        raise HTTPException(
            status_code=400,
            detail=f"无效块索引，最大允许值：{total_pages // BLOCK_SIZE}"
        )

    # 生成分块PDF
    writer = PdfWriter()
    for i in range(start_page, end_page):
        writer.add_page(reader.pages[i])
    
    output_stream = BytesIO()
    writer.write(output_stream)
    output_stream.seek(0)

    # 添加调试日志
    app_logger.info(
        f"返回块 {block_index}: 页码 {start_page+1}-{end_page} "
        f"(总页数: {total_pages})"
    )
    encoded_filename = quote(f"{material.title}_block_{block_index}.pdf")
    return StreamingResponse(
        output_stream,
        media_type="application/pdf",
        headers={
            "Content-Disposition": f"attachment;filename*=UTF-8''{encoded_filename}",
            "X-Total-Pages": str(total_pages),  # 添加额外元数据
            "X-Current-Block": str(block_index)
        }
    )

@router.get("/", response_model=list[MaterialResponse])
def read_all_materials(db: Session = Depends(get_db), current_user: LearnUser = Depends(get_current_user)):
    response = get_all_materials(db, current_user.id)
    return [MaterialResponse(
        id=material.id,
        title=material.title,
        created_at=material.created_at
    ) for material in response]


@router.put("/{material_id}", response_model=MaterialResponse)
def modify_material(material_id: int, title: str, file_path: str, db: Session = Depends(get_db), current_user: LearnUser = Depends(get_current_user)):
    updated_material = update_material(db, material_id, title, file_path, current_user.id)
    if not updated_material:
        raise HTTPException(status_code=404, detail="文档材料不存在")
    return MaterialResponse(
        id=updated_material.id,
        title=updated_material.title,
        created_at=updated_material.created_at
    )


@router.delete("/{material_id}")
def remove_material(material_id: int, db: Session = Depends(get_db), current_user: LearnUser = Depends(get_current_user)):
    # 先获取材料信息
    material = get_material(db, material_id, current_user.id)
    if not material:
        raise HTTPException(status_code=404, detail="文档材料不存在")
    
    # 构建完整的文件路径
    file_path = UPLOAD_DIR / material.file_path
    app_logger.info(f"删除文件路径: {file_path}")
    
    # 删除文件
    try:
        if file_path.exists():
            file_path.unlink()
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"删除文件失败: {str(e)}")
    
    # 删除数据库记录
    if delete_material(db, material_id, current_user.id):
        return {"message": "文档材料成功删除"}
    raise HTTPException(status_code=404, detail="文档材料不存在")

